#ifndef GAME_LEVEL_H_
#define GAME_LEVEL_H_

#include "updatable.h"
#include "actor_desc.h"
#include "game_camera_desc.h"
#include "actor.h"
#include "game_camera.h"
#include <string>
#include <vector>
#include <map>

namespace rpg {

	class GameLevel : public Updatable {
	public:
		GameLevel(void);
		GameLevel(const Ogre::String &name);
		~GameLevel(void);

		Ogre::String getName(void) const;
		void setName(const Ogre::String &name);

		bool isActor(const Ogre::String &actorName) const;
		Actor * getActorByName(const Ogre::String &actorName);
		Actor * addNewActor(const ActorDesc &actorDesc);
		void removeActor(const Ogre::String &actorName);

		bool isCamera(const Ogre::String &cameraName) const;
		GameCamera * getCameraByName(const Ogre::String &cameraName);
		GameCamera * addNewCamera(const GameCameraDesc &gameCameraDesc);
		void removeCamera(const Ogre::String &cameraName);
		GameCamera * getActiveCamera(void);
		void setActiveCamera(const Ogre::String &cameraName);

		void buildWaypoint(const Ogre::Vector3 &startPoint, const Ogre::Vector3 &endPoint, std::list<Ogre::Vector3> *waypoint) const;

		void update(float deltaTime);
	private:
		template<class T>
		class FindObjectByName {
		public:
			FindObjectByName(const Ogre::String &name);

			bool operator () (T *object);
		private:
			Ogre::String mName;
		};

		template<class T>
		class LevelObjectUpdater {
		public:
			LevelObjectUpdater(float deltaTime);

			void operator () (T *object);
		private:
			float mDeltaTime;
		};

		class VectorAnglesComparator {
		public:
			VectorAnglesComparator(const Ogre::Vector3 &customVector);

			bool operator () (const Ogre::Vector3 &v1, const Ogre::Vector3 &v2) const;
		private:
			Ogre::Vector3 mCustomVector;
		};

		Ogre::String mName;

		std::vector<Actor *> mActorList;
		std::map<Ogre::String, Actor *> mActorSearchMap;

		GameCamera *mActiveCamera;
		std::vector<GameCamera *> mCameraList;
		std::map<Ogre::String, GameCamera *> mCameraSearchMap;
	};

	template<class T>
	GameLevel::FindObjectByName<T>::FindObjectByName(const Ogre::String &name) : mName(name) {
	}

	template<class T>
	bool GameLevel::FindObjectByName<T>::operator () (T *object) {
		return (Ogre::String(object->getName()) == mName);
	}

	template<class T>
	GameLevel::LevelObjectUpdater<T>::LevelObjectUpdater(float deltaTime) : mDeltaTime(deltaTime) {
	}

	template<class T>
	void GameLevel::LevelObjectUpdater<T>::operator () (T *object) {
		object->update(mDeltaTime);
	}

}

#endif /* GAME_LEVEL_H_ */
